package game.objects;
import org.lwjgl.input.Keyboard;

import physics.Body;
import physics.collision.RayCastInfo;
import physics.joints.JAngleJoint;
import physics.joints.JBackgroundAngleJoint;
import physics.joints.JDistanceJoint;
import physics.joints.JSpring;
import physics.joints.Joint;
import physics.tools.Initializer;

import sound.main.Sound;
import sound.main.SoundManager;
import tools.Floatmath;
import tools.Help;
import tools.Point;
import editors.objectedit.BoundingBox;
import editors.objectedit.LoadObject;
import game.Game;
import game.controlling.Controller;
import game.engine.Empty;
import game.engine.GSync;
import game.objects.Kinematics.AnimState;
import game.objects.interfaces.Damageable;
import game.objects.interfaces.Ownable;
import graphics.effects.Compositor;
import graphics.effects.GEExplosion;
import graphics.effects.GEFlashLight;
import graphics.objects.GLine;
import graphics.objects.GPointLight;
import graphics.objects.GShape;
import graphics.objects.GraphicsObject;
import graphics.system.Color;
public class GOPlayer extends GameObject implements Ownable, Damageable {
	private static final float SHOOTDELAY = 2.0f;
	private static final float JUMPDELAY = 0.5f;
	
	private int ownerId;
	private float shoottime;
	private GLine line;
	private float jumptime;
	public Figure figure;
	Kinematics kin;
	private boolean dead;
	private Point campos;
	private boolean jointsdeleted;
	public GOPlayer(Game g, Point pos) {
		super(g, pos, 0);
		figure = new Figure();
		kin = new Kinematics(figure);
		campos = new Point();
		jointsdeleted = false;
	}
	@Override
	public void control(Controller c) {
		if (dead)
			return;
		shootRocket(c);
		walk(c);
		shoot(c);
		jump(c);
		calcCampos(c);
		kin.lookAt(c.getMp());
		if (line != null) {
			line.color.a *= 0.5f;
			if (line.color.a < 0.1) {
				// this.remGraphicsObject(line);
				line = null;
			}
		}
	}
	private void calcCampos(Controller c) {
		Point dx = null;
		if (!dead)
			dx = figure.body.pos.sub(c.getMp());
		else
			dx = new Point();
		float f = Math.min(1, campos.distance(figure.body.pos.add(dx.mul(-0.4f))) / 2000);
		campos = campos.mul(1 - f).add(figure.body.pos.add(dx.mul(-0.4f)).mul(f));
	}
	private void walk(Controller c) {
		if (c.pressedGame("left")) {
			Point force = new Point(-5000, 0);
			getBody(0).applyForce(force);
			kin.setState(AnimState.WALKLEFT);
		}
		else if (c.pressedGame("right")) {
			Point force = new Point(5000, 0);
			getBody(0).applyForce(force);
			kin.setState(AnimState.WALKRIGHT);
		}
		else {
			kin.setState(AnimState.STAND);
		}
	}
	private void shoot(Controller c) {
		if (c.pressedGame("shoot2") && game.time - shoottime > SHOOTDELAY) {
			shoottime = game.time;
			Point dx = c.getMp().sub(figure.body.pos);
			for (int i = 0; i < this.numBodies; i++) {
				getBody(i).pos.sAdd(dx);
			}
		}
	}
	private void jump(Controller c) {
		if (c.pressedGame("jump")) {
			if (game.time - this.jumptime > JUMPDELAY) {
				jumptime = game.time;
				figure.body.applyImpulse(new Point(0, 6000));
				figure.head.applyImpulse(new Point(0, 1000));
			}
			else if (game.time - this.jumptime < JUMPDELAY) {
				kin.setState(AnimState.JUMP);
			}
		}
	}
	private void shootRocket(Controller c) {
		if (c.pressedGame("shoot") && game.time - shoottime > SHOOTDELAY) {
			Point dir = c.getMp().sub(getBody(0).pos).normalize();
			RayCastInfo ri = castRay(figure.body.pos, dir, 80);
			if (ri != null) {
				// ri.body.applyImpulse(dir.mul(1000));
				addGraphicsObject(new GEFlashLight(figure.body.pos.add(dir.mul(80)), 100, new Color(1, 0, 0, 0.3f)), new GSync());
				addGraphicsObject(new GEFlashLight(ri.pos.sub(dir.mul(5)), 200, Color.red), new GSync());
				// body.applyImpulse(dir.mul(-1000));
				if (line != null) {
					this.remGraphicsObject(line);
				}
				line = new GLine(ri.pos, figure.body.pos.add(dir.mul(80)), 2, new Color(1, 0, 0, 1));
				line.setGlow(true);
				line.setGlowScale(10);
				line.glowColor = new Color(1, 1, 0, 1);
				 //this.addGraphicsObject(line, new GSync());
				
			}
			GORocket rocket = new GORocket(game, figure.body.pos.add(dir.mul(80)), dir.angle());
			game.addGameObject(rocket);
			shoottime = game.time;
		}
	}
	@Override
	public void initialize(Point pos, float angle) {
		LoadObject.load("human", this, pos);
		for (int i = 0; i < numJoints; i++) {
			Joint j = getJoint(i);
			if (j instanceof JDistanceJoint) {
				((JDistanceJoint) j).setLength(0.0f);
			}
		}
		figure.body = getBodyByName("body");
		figure.head = getBodyByName("head");
		figure.rLegUp = getBodyByName("r_legup");
		figure.rLegDown = getBodyByName("r_legdown");
		figure.lLegUp = getBodyByName("l_legup");
		figure.lLegDown = getBodyByName("l_legdown");
		figure.rFoot = getBodyByName("r_feet");
		figure.lFoot = getBodyByName("l_feet");
		figure.rArmUp = getBodyByName("r_armup");
		figure.rArmDown = getBodyByName("r_armdown");
		figure.rHand = getBodyByName("r_hand");
		figure.lArmUp = getBodyByName("l_armup");
		figure.lArmDown = getBodyByName("l_armdown");
		figure.lHand = getBodyByName("l_hand");
		figure.rFoot.friction = 0.5f;
		figure.lFoot.friction = 0.5f;
		addMuscles();
		/*
		 * GPointLight l = new GPointLight(figure.head.pos,1500,new Color(1,1,0.9f,0.8f)); addGraphicsObject(l,new GSync(figure.head));
		 */
		/*
		 * for (int i = 0; i < numJoints; i++) { getJoint(i).setStrength(1f); }
		 */
		for (int i = 0; i < numBodies - 1; i++) {
			getBody(i).mass = 5;
			for (int j = i + 1; j < numBodies; j++) {
				getBody(i).setNonColliding(getBody(j));
			}
		}
		kin.setWalkingDir(-1);
	}
	private void addMuscles() {
		figure.bodyAngle = new JBackgroundAngleJoint(figure.body, 0.0f);
		figure.headAngle = new JAngleJoint(figure.body, figure.head, 0.0f);
		figure.rLegUpAngle = new JAngleJoint(figure.body, figure.rLegUp, 0.0f);
		figure.rLegDownAngle = new JAngleJoint(figure.rLegUp, figure.rLegDown, 0.0f);
		figure.rFootAngle = new JAngleJoint(figure.rLegDown, figure.rFoot, 0.0f);
		figure.lLegUpAngle = new JAngleJoint(figure.body, figure.lLegUp, 0.0f);
		figure.lLegDownAngle = new JAngleJoint(figure.lLegUp, figure.lLegDown, 0.0f);
		figure.lFootAngle = new JAngleJoint(figure.lLegDown, figure.lFoot, 0.0f);
		figure.rArmUpAngle = new JAngleJoint(figure.body, figure.rArmUp, 0.0f);
		figure.rArmDownAngle = new JAngleJoint(figure.rArmUp, figure.rArmDown, 0.0f);
		figure.rHandAngle = new JAngleJoint(figure.rArmDown, figure.rHand, 0.0f);
		figure.lArmUpAngle = new JAngleJoint(figure.body, figure.lArmUp, 0.0f);
		figure.lArmDownAngle = new JAngleJoint(figure.lArmUp, figure.lArmDown, 0.0f);
		figure.lHandAngle = new JAngleJoint(figure.lArmDown, figure.lHand, 0.0f);
		addJoint(figure.bodyAngle);
		addJoint(figure.headAngle);
		addJoint(figure.rLegUpAngle);
		addJoint(figure.rLegDownAngle);
		addJoint(figure.rFootAngle);
		addJoint(figure.lLegUpAngle);
		addJoint(figure.lLegDownAngle);
		addJoint(figure.lFootAngle);
		addJoint(figure.rArmUpAngle);
		addJoint(figure.rArmDownAngle);
		addJoint(figure.rHandAngle);
		addJoint(figure.lArmUpAngle);
		addJoint(figure.lArmDownAngle);
		addJoint(figure.lHandAngle);
	}
	@Override
	public void handle() {
		kin.handle();
	}
	@Override
	public int getOwner() {
		return ownerId;
	}
	@Override
	public void setOwner(int ownerId) {
		this.ownerId = ownerId;
	}
	public Point getPosition() {
		if (figure.body != null)
			return figure.body.pos;
		return null;
	}

	@Override
	public void destroy() {
		if (!dead) {
			dead = true;
			Help.p("DEAD!!!");
			if (game.server) {
				remJoint(figure.bodyAngle);
				for (int i = 0; i < numJoints; i++) {
					if (Floatmath.random() < 0.3f) {
						remJoint(getJoint(i));
						i--;
					}
				}
			}
			this.kin.setState(AnimState.STAND);
			Compositor.setMblur(0.91f);
		}
	}
	public Point getCameraPosition() {
		return campos;
	}
	public float getViewDistance() {
		// TODO set through weapon/vehicle ...
		return 2000;
	}
}
